﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

using NetBpm.Util.Client;
using NetBpm.Workflow.Organisation.EComp;
using NetBpm.Workflow.Organisation;
using NetBpm.Workflow.Delegation;
using NetBpm.Workflow.Definition;
using NetBpm.Workflow.Definition.EComp;
using NetBpm.Workflow.Execution;
using NetBpm.Workflow.Execution.EComp;
using NetBpm.Workflow.Definition.Attr;
using NetBpm.Workflow.Log.EComp;
using NetBpm.Workflow.Log;

namespace BEGDC.CC.Web
{
	/// <summary>
	/// Summary description for ProcessExecute.
	/// </summary>
	public class ProcessExecute : System.Web.UI.Page
	{
		protected System.Web.UI.WebControls.TextBox TextBox1;
		protected System.Web.UI.WebControls.TextBox TextBox2;
		protected System.Web.UI.WebControls.Button Button1;
		protected System.Web.UI.WebControls.Button Button2;
		protected System.Web.UI.WebControls.Button Button3;
		protected System.Web.UI.WebControls.Button Button4;
		protected System.Web.UI.WebControls.DataGrid DataGrid2;
		protected System.Web.UI.WebControls.Button Button5;
		protected System.Web.UI.WebControls.Button Button6;
		protected System.Web.UI.WebControls.DropDownList DropDownList1;
		protected System.Web.UI.WebControls.DropDownList DropDownList2;
		protected System.Web.UI.WebControls.DataGrid DataGrid1;
	
		private void Page_Load(object sender, System.EventArgs e)
		{
			if (!this.IsPostBack)
			{
				if (this.Request.QueryString["processDefinitionId"] != null)
				{
					this.StartProcess();
					
				
				}
				this.LoadTasks();
				this.LoadStates();
			}
			
		}

		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);
		}
		
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{    
			this.Button1.Click += new System.EventHandler(this.Button1_Click);
			this.Button2.Click += new System.EventHandler(this.Button2_Click);
			this.Button3.Click += new System.EventHandler(this.Button3_Click);
			this.Button4.Click += new System.EventHandler(this.Button4_Click);
			this.Button5.Click += new System.EventHandler(this.Button5_Click);
			this.Button6.Click += new System.EventHandler(this.Button6_Click);
			this.DropDownList2.SelectedIndexChanged += new System.EventHandler(this.DropDownList2_SelectedIndexChanged);
			this.Load += new System.EventHandler(this.Page_Load);

		}
		#endregion

		private void LoadStates()
		{
			BEGDC.CC.BL.Workflow.IDefinition def = BEGDC.Utility.Castle.AppContainer.Instance[BEGDC.CC.BL.Common.ServiceConst.DefinitionService] as BEGDC.CC.BL.Workflow.IDefinition;
			BEGDC.CC.BL.Workflow.ProcessStateList states = def.GetDefinition(this.DropDownList2.SelectedValue);

			this.DropDownList1.Items.Clear();

			for(int i=0; i<states.Count; i++)
			{
				BEGDC.CC.BL.Workflow.ProcessState state = states[i];
				for(int j=0; j<state.ChildrenStates.Count; j++)
				{
					this.DropDownList1.Items.Add(new ListItem(state.ChildrenStates[j].Key, state.ChildrenStates[j].ID.ToString()));
				}
			}
			
		}

		private void LoadTasks()
		{
			IExecutionSessionLocal executionComponent = null;
			try
			{
				DataTable dt = new DataTable("TaskList");
				DataColumn dc1 = new DataColumn("FlowID",typeof(Int64));
				DataColumn dc2 = new DataColumn("ProcessName");
				DataColumn dc3 = new DataColumn("ActivityName");
				DataColumn dc4 = new DataColumn("Date");
				DataColumn dc5 = new DataColumn("Description");
				DataColumn dc6 = new DataColumn("ProcessInstanceId",typeof(int));
				DataColumn dc7 = new DataColumn("DefinitionName");
				DataColumn dc8 = new DataColumn("DefinitionId",typeof(int));
				
				dt.Columns.Add(dc1);
				dt.Columns.Add(dc2);
				dt.Columns.Add(dc3);
				dt.Columns.Add(dc4);
				dt.Columns.Add(dc5);
				dt.Columns.Add(dc6);
				dt.Columns.Add(dc7);
				dt.Columns.Add(dc8);


				executionComponent = ServiceLocator.Instance.GetService(typeof (IExecutionSessionLocal)) as IExecutionSessionLocal;

				//executionComponent.GetTaskList(
//				ArrayList actors = new ArrayList();
//				actors.Add(this.Page.User.Identity.Name);
				ArrayList actors = new ArrayList();
				actors.Add(this.Page.User.Identity.Name);
			
				foreach(string role in BEGDC.CC.BL.Workflow.Configuration.RoleGroups)
				{
					if (this.Page.User.IsInRole(role))
						actors.Add(role);
				}
				IList tasks = executionComponent.GetTaskList(actors);
			
				if(tasks!=null)
				{            
					DataRow dr;
					foreach(IFlow flow in tasks)
					{
						IProcessInstance inst = (IProcessInstance)flow.ProcessInstance;
						IProcessDefinition def = (IProcessDefinition)inst.ProcessDefinition;    
							
						dr = dt.NewRow();
						dr["FlowID"] = flow.Id;
						dr["ProcessName"] = flow.ProcessInstance.ProcessDefinition.Name;
						dr["ActivityName"] = flow.Node.Name;
						dr["Date"] = flow.ProcessInstance.Start.Date;					
						dr["Description"] = flow.ProcessInstance.ProcessDefinition.Description;
						dr["ProcessInstanceId"] = flow.ProcessInstance.Id;
						dr["DefinitionName"] = def.Name;
						dr["DefinitionId"] = def.Id;
						dt.Rows.Add(dr);
					}
				}
				this.DataGrid1.DataSource = dt;
				this.DataGrid1.DataBind();

				// this means that it is a start-activity being performed so we have to 
				// start a new process instance
				//IDictionary attributeValues = new Hashtable();				
				//IProcessInstance processInstance = executionComponent.StartProcessInstance(processid, attributeValues );

				//executionComponent.GetFlow(
				
				//processInstance.RootFlow.
				//executionComponent.PerformActivity(processInstance.RootFlow.Id);
				
			}
			catch(Exception ex)
			{
				throw new Exception (ex.Message);
			}
			finally
			{
				ServiceLocator.Instance.Release(executionComponent);
			}
		}

		private void StartProcess()
		{
			IExecutionSessionLocal executionComponent = null;
			try
			{
				int processid = Int32.Parse(this.Request.QueryString["processDefinitionId"]);
                executionComponent = ServiceLocator.Instance.GetService(typeof (IExecutionSessionLocal)) as IExecutionSessionLocal;
				// this means that it is a start-activity being performed so we have to 
				// start a new process instance
				IDictionary attributeValues = new Hashtable();				
				IProcessInstance processInstance = executionComponent.StartProcessInstance(processid, attributeValues );
		}
			catch(Exception ex)
			{
				throw new Exception (ex.Message);
			}
			finally
			{
				ServiceLocator.Instance.Release(executionComponent);
			}
		}

		private void ExecuteWorkflow()
		{
			IExecutionSessionLocal executionComponent = null;
			try
			{
				int workflowid = Int32.Parse(this.TextBox1.Text);
				executionComponent = ServiceLocator.Instance.GetService(typeof (IExecutionSessionLocal)) as IExecutionSessionLocal;
				
				IDictionary attributeValues = new Hashtable();				
				
				attributeValues.Add("NextTransition", this.TextBox2.Text);				

				IList flows = null;
				flows = executionComponent.PerformActivity(workflowid, attributeValues);
				
				if (flows.Count > 0)
				{
					IFlow flow = (IFlow)flows[0];
					string status = flow.Node.Name;
					string owner = "";
					Type curtype = flow.Node.GetType();
					Type endtype = typeof(NetBpm.Workflow.Definition.Impl.EndStateImpl);
					if (curtype.Equals(endtype) || curtype.IsSubclassOf(endtype))
						owner = "N/A";
					else
						owner = flow.GetActor().Name;
					//Update Project Status
					System.Diagnostics.Debug.WriteLine(status+"|"+owner);
				}
			}
			catch(Exception ex)
			{
				throw new Exception (ex.Message);
			}
			finally
			{
				ServiceLocator.Instance.Release(executionComponent);
			}
		}

		private void Button1_Click(object sender, System.EventArgs e)
		{
			this.ExecuteWorkflow();
			this.LoadTasks();
		}

		private void Button2_Click(object sender, System.EventArgs e)
		{
			IExecutionSessionLocal executionComponent = null;
			try
			{
				int workflowid = Int32.Parse(this.TextBox1.Text);
				executionComponent = ServiceLocator.Instance.GetService(typeof (IExecutionSessionLocal)) as IExecutionSessionLocal;
				
				executionComponent.CancelFlow(workflowid);
			}
			catch(Exception ex)
			{
				throw new Exception (ex.Message);
			}
			finally
			{
				ServiceLocator.Instance.Release(executionComponent);
			}
			this.LoadTasks();
		}

		private void Button3_Click(object sender, System.EventArgs e)
		{
			IExecutionSessionLocal executionComponent = null;
			try
			{
				int workflowid = Int32.Parse(this.TextBox1.Text);
				executionComponent = ServiceLocator.Instance.GetService(typeof (IExecutionSessionLocal)) as IExecutionSessionLocal;
				
				executionComponent.CancelProcessInstance(workflowid);
			}
			catch(Exception ex)
			{
				throw new Exception (ex.Message);
			}
			finally
			{
				ServiceLocator.Instance.Release(executionComponent);
			}
			this.LoadTasks();
		}

		private void Button4_Click(object sender, System.EventArgs e)
		{
			ILogSessionLocal logComponent = ServiceLocator.Instance.GetService(typeof (ILogSessionLocal)) as ILogSessionLocal;
			try 
			{				
				DataTable dt = new DataTable("ProcessInstance");
				DataColumn dc1 = new DataColumn("FlowName");
				//				DataColumn dc2 = new DataColumn("ProcessInstanceID");
				DataColumn dc2 = new DataColumn("EvaluationResult");
				DataColumn dc3 = new DataColumn("Activitystate");
				DataColumn dc4 = new DataColumn("Time");
				DataColumn dc5 = new DataColumn("Actor");
				//				DataColumn dc6 = new DataColumn("Role");
				DataColumn dc6 = new DataColumn("Comment");
				
				dt.Columns.Add(dc1);
				dt.Columns.Add(dc2);
				dt.Columns.Add(dc3);
				dt.Columns.Add(dc4);
				dt.Columns.Add(dc5);
				dt.Columns.Add(dc6);
				//dt.Columns.Add(dc7);

				IFlow flow = logComponent.GetFlow(Convert.ToInt64(this.TextBox1.Text));
				WriteFlow(dt, flow);
				
				DataView dv = dt.DefaultView;
				dv.Sort = "[Time]";
				this.DataGrid2.DataSource = dt;
				this.DataGrid2.DataBind();
			} 
			finally
			{
				ServiceLocator.Instance.Release(logComponent);
			}
		}

		private void WriteFlow(DataRow dr, IFlow flow)
		{
			IEnumerator iter = flow.Logs.GetEnumerator();
			//@todo add sort see http://www.koders.com/csharp/fid7483E2E4A14A57A929B3D9338410A60E4E911842.aspx?s=sort
			while (iter.MoveNext())
			{
				ILog eventLog = (ILog) iter.Current;
				WriteFlowEvent(dr, eventLog, flow);
			}
			
		}

		private void WriteFlow(DataTable dt, IFlow flow)
		{
			IEnumerator iter = flow.Logs.GetEnumerator();
			//@todo add sort see http://www.koders.com/csharp/fid7483E2E4A14A57A929B3D9338410A60E4E911842.aspx?s=sort
			DataRow dr;
			while (iter.MoveNext())
			{
				dr = dt.NewRow();
				ILog eventLog = (ILog) iter.Current;
				WriteFlowEvent(dr, eventLog, flow);
				if(dr.ItemArray.Length>0 && dr[0]!= System.DBNull.Value)
					dt.Rows.Add(dr);
			}
		}

		
		private void  WriteFlowEvent(DataRow dr, ILog eventLog, IFlow flow)
		{
			if (eventLog.EventType == EventType.SUB_PROCESS_INSTANCE_START)
			{
				IObjectReference objectReference = (IObjectReference) eventLog.GetObjectReferences("ProcessInstance").GetEnumerator().Current;
				IProcessInstance subProcessInstance = (IProcessInstance) objectReference.GetObject();
				IFlow subFlow = subProcessInstance.RootFlow;
				WriteFlow(dr, subFlow);
			}
			else if(eventLog.EventType == EventType.PERFORM_OF_ACTIVITY ||
				eventLog.EventType == EventType.PROCESS_INSTANCE_START)
			{
				// if it is no fork or subprocess, log the details
				IEnumerator iter = eventLog.Details.GetEnumerator();
				string _name = string.Empty;
				string _value = string.Empty;
				while (iter.MoveNext())
				{
					dr["FlowName"] = eventLog.EventType;
					//IDefinitionObject def = (IDefinitionObject)flow.ProcessInstance.ProcessDefinition;
					//dr["FlowName"] = def.Name;
					dr["Time"] = eventLog.Date.ToString();
			
					IActor actor = eventLog.GetActor();
					if (actor != null)
					{
						//Domain.Data.IMUser user = CommonFacade.GetUser(int.Parse(actor.Id));
						//dr["Actor"] = user.LASTNAME + " " + user.FIRSTNAME;
						dr["Actor"] = actor.Name;
					}
					if(eventLog.EventType == EventType.PROCESS_INSTANCE_START)
					{
						dr["Activitystate"] = "Applied";
					}
					ILogDetail logDetail = (ILogDetail)iter.Current;
					if (logDetail is IAttributeUpdate)
					{
						IAttributeUpdate attributeUpdate = (IAttributeUpdate) logDetail;
						_name = ""+attributeUpdate.Attribute.Name;
						_value = ""+attributeUpdate.GetValue();
						if(_name.ToLower().IndexOf("evaluation")>-1)
						{
							dr["EvaluationResult"] = _value;
						}
						else if(_name.ToLower().IndexOf("comment")>-1)
						{
							dr["Comment"] = _value;
						}
					}
					else if (logDetail is IObjectReference)
					{
						IObjectReference objectReference = (IObjectReference) logDetail;
						System.Object object_Renamed = objectReference.GetObject();
						if (object_Renamed is IActivityState)
						{
							IActivityState activityState = (IActivityState) object_Renamed;
							//dr["Activitystate"] = FlowUtil.GetAction(activityState.Name);
							try
							{
								//int stepId = int.Parse(activityState.Name);
								dr["Activitystate"]= activityState.Name;//CommonFacade.GetWorkFlowStep(activityState.ProcessDefinition.Name,stepId).Result;
							}
							catch
							{
								if(activityState.Name.ToLower()=="start")
									dr["Activitystate"] = "Re-applied";
								else
									dr["Activitystate"] = activityState.Name;
							}
							
						}
						else
						{
							//log.Warn("unknown object reference type : " + object_Renamed);
						}
					}

				}
			}
			
			
		}

		private void Button5_Click(object sender, System.EventArgs e)
		{
			IExecutionSessionLocal executionComponent = null;
			try
			{
				int workflowid = Int32.Parse(this.TextBox1.Text);
				executionComponent = ServiceLocator.Instance.GetService(typeof (IExecutionSessionLocal)) as IExecutionSessionLocal;				
				executionComponent.DrawbackActivity(workflowid, null, null);
			}
			catch(Exception ex)
			{
				throw new Exception (ex.Message);
			}
			finally
			{
				ServiceLocator.Instance.Release(executionComponent);
			}
			this.LoadTasks();
		}

		private void Button6_Click(object sender, System.EventArgs e)
		{
			IExecutionSessionLocal executionComponent = null;
			try
			{
				int workflowid = Int32.Parse(this.TextBox1.Text);
				executionComponent = ServiceLocator.Instance.GetService(typeof (IExecutionSessionLocal)) as IExecutionSessionLocal;
				
				long destStateId = Convert.ToInt64(this.DropDownList1.SelectedValue);				
				

				IList flows = null;
				flows = executionComponent.MoveFlowState(workflowid, destStateId);
				
				if (flows.Count > 0)
				{
					IFlow flow = (IFlow)flows[0];
					string status = flow.Node.Name;
					string owner = "";
					Type curtype = flow.Node.GetType();
					Type endtype = typeof(NetBpm.Workflow.Definition.Impl.EndStateImpl);
					if (curtype.Equals(endtype) || curtype.IsSubclassOf(endtype))
						owner = "N/A";
					else
						owner = flow.GetActor().Name;
					//Update Project Status
					System.Diagnostics.Debug.WriteLine(status+"|"+owner);
				}
			}
			catch(Exception ex)
			{
				throw new Exception (ex.Message);
			}
			finally
			{
				ServiceLocator.Instance.Release(executionComponent);
			}
			this.LoadTasks();
		}

		private void DropDownList2_SelectedIndexChanged(object sender, System.EventArgs e)
		{
            this.LoadStates();		
		}

	
		
	}
}
